#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <queue>
#include "task.h"
#include <time.h>
using namespace std;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t p_cond = PTHREAD_COND_INITIALIZER;

template <class T>
class dataQueue
{
public:
    void push(const T &data)
    {
        pthread_mutex_lock(&mutex);

        while (_q.size() >= _size)
        {
            //pthread_cond_signal(&c_cond); // 唤醒消费者
            pthread_cond_wait(&p_cond, &mutex);
        }
        _q.push(data);

        pthread_cond_signal(&c_cond); // 唤醒消费者
        pthread_mutex_unlock(&mutex);
    }

    T pop()
    {
        pthread_mutex_lock(&mutex);

        while (_q.size() == 0)
        {
            // pthread_cond_signal(&p_cond); // 唤醒生产者
            pthread_cond_wait(&c_cond, &mutex);
        }
        T front = _q.front();
        _q.pop();

        pthread_cond_signal(&p_cond); // 唤醒生产者
        pthread_mutex_unlock(&mutex);

        return front;
    }

private:
    queue<T> _q;
    int _size = 5; // 这是我们控制的一个队列中最多可以容纳的数据量
};

dataQueue<task> q;

struct threadData
{
    string _threadName;
    threadData(string name)
        : _threadName(name)
    {
    }
    threadData() = default;
};

void *productor(void *args)
{
    threadData *data = static_cast<threadData *>(args);
    srand(time(nullptr));
    char opr[] = "+-*/%";
    int i = 0;
    while (true)
    {
        int x = rand() % 10;
        usleep(10);
        int y = rand() % 10;
        task t(x, y, opr[i % 5]);
        i++;
        printf("thread tid : %p %s \n", pthread_self(), t.getFun().c_str());
        q.push(t);
        sleep(1);
    }
}

void *consumer(void *args)
{
    threadData *data = static_cast<threadData *>(args);
    while (true)
    {
        task t = q.pop();
        t.fun();
        printf("thread tid : %p %s \n", pthread_self(), t.getAnswer().c_str());
    }
}

int main()
{
    pthread_t tid;
    vector<pthread_t> tids;
    for (int i = 0; i < 3; i++)
    {
        threadData *data = new threadData("comsumer");
        pthread_create(&tid, nullptr, consumer, data);
        tids.push_back(tid);
    }

    for (int i = 0; i < 3; i++)
    {
        threadData *data = new threadData("productor");
        pthread_create(&tid, nullptr, productor, data);
        tids.push_back(tid);
    }

    void *retData;
    for (auto tid : tids)
    {
        pthread_join(tid, &retData);
    }

    return 0;
}